package main

import (
	"context"
	"fmt"
	"go.etcd.io/etcd/clientv3"
	"time"
)

func main() {
	var (
		config clientv3.Config
	)

	config = clientv3.Config{
		Endpoints:   []string{"127.0.0.1:2379"},
		DialTimeout: 5 * time.Second, // 超时时间
	}

	// 建立连接
	client, err := clientv3.New(config)
	if err != nil {
		fmt.Println(err)
		return
	}

	// 1 上锁 创建租约，拿着租约去抢占一个key
	lease := clientv3.NewLease(client)

	leaseResp, err := lease.Grant(context.TODO(), 10) // 申请一个10秒钟的租约
	if err != nil {
		fmt.Println(err)
		return
	}

	leaseId := leaseResp.ID // 拿到租约ID

	// 自动续约
	keepRespChan, err := lease.KeepAlive(context.TODO(), leaseId)
	if err != nil {
		fmt.Println(err)
		return
	}

	go func() {
		for {
			select {
			case keepResp := <-keepRespChan:
				if keepResp != nil {
					fmt.Println("收到租约应答", keepResp.ID)
				} else {
					fmt.Println("租约已经失效了")
					goto END
				}

			}
		}
	END:
	}()

	kv := clientv3.NewKV(client)

	// 创建事务
	txn := kv.Txn(context.TODO())

	// 定义事务
	// if 不存在key，then 设置它，else 抢锁失败
	txn.If(clientv3.Compare(clientv3.CreateRevision("/cron/lock/job9"), "=", 0)). // 当key值得版本号为0的时候（不存在的revision都为0）
											Then(clientv3.OpPut("/cron/lock/job9", "xxx", clientv3.WithLease(leaseId))). // 创建一个key
											Else(clientv3.OpGet("/cron/lock/job9"))                                      // 抢锁失败

	txnResp, err := txn.Commit()
	if err != nil {
		fmt.Println(err)
		return
	}

	// 判断是否抢到了锁
	if !txnResp.Succeeded {
		fmt.Println("锁被占用:", string(txnResp.Responses[0].GetResponseRange().Kvs[0].Value))
		return
	}

	fmt.Println("处理任务")
	time.Sleep(5 * time.Second)

	// 释放锁（取消续约）
	lease.Revoke(context.TODO(), leaseId)

	// 判断key是否存在
	resp, err := kv.Get(context.TODO(), "/cron/lock/job9")
	if err != nil {
		fmt.Println(err)
		return
	}
	if len(resp.Kvs) != 0 {
		fmt.Println(resp.Header.Revision)
	} else {
		fmt.Println("锁已被删除")
	}
}
